#pragma once
#include <iostream>
#include <string>
#include "Sock.hpp"
#include "Epoller.hpp"

const static uint16_t default_port = 8888;

class EpollServer
{
    const static int num = 64;

public:
    EpollServer(uint16_t port = default_port)
        : _port(port)
    {
    }

    void InitServer()
    {
        _listensock.Socket();
        _listensock.Bind(_port);
        _listensock.Listen();
        _epoll.Create();
    }

    void Start()
    {
        _epoll.AddEvent(_listensock.GetFd(), EPOLLIN);
        int timeout = -1;
        while (true)
        {
            int n = _epoll.Wait(events, num, timeout);
            switch (n)
            {
            case 0:
                LogMessage(Info, "time out, %d: %s", errno, strerror(errno));
                break;
            case -1:
                LogMessage(Warring, "%d: %s", errno, strerror(errno));
                break;
            default:
                LogMessage(Info, "There are %d things ready", n);
                HandlerEvent(n);
                break;
            }
        }
    }

    ~EpollServer()
    {
    }

private:
    void HandlerEvent(int n)
    {
        for (int i = 0; i < n; i++)
        {
            int fd = events[i].data.fd;
            uint32_t event = events[i].events;

            if (event & EPOLLIN)
            {
                if (fd == _listensock.GetFd())
                {
                    std::string client_ip;
                    uint16_t client_port;
                    int sock = _listensock.Accept(&client_ip, &client_port);
                    if (sock < 0) continue;
                    
                    LogMessage(Info, "%s:%d, connect on server...", client_ip.c_str(), client_port);
                    _epoll.AddEvent(sock, EPOLLIN);
                }
                else
                {
                    char buffer[1024];
                    int n = read(fd, buffer, sizeof(buffer) - 1);
                    if (n > 0)
                    {
                        buffer[n - 1] = 0;
                        buffer[n - 2] = 0;
                        std::cout << "client# " << buffer << std::endl;
                        // echo
                        // 重构 connection LoopOnce
                        std::string sendstr = buffer;
                        sendstr += "[server]\r\n";
                        send(fd, sendstr.c_str(), sendstr.size(), 0);
                    }
                    else if (n == 0)
                    {
                        LogMessage(Info, "client quit..., sock: %d", fd);
                        // 必须先删除，因为接口内部的使用不允许fd非法
                        _epoll.DelEvent(fd);
                        close(fd);
                    }
                    else
                    {
                    }
                }
            }
        }
    }

private:
    Sock _listensock;
    uint16_t _port;
    Epoller _epoll;
    struct epoll_event events[num];
};